#ifndef     __MESSAGE_H
#define     __MESSAGE_H

#include "./codec.h"
#include "../driver/ble_uart.h"
#include "../driver/cmd_uart.h"
#include "../driver/log_uart.h"

namespace utils {

struct message_t {

    enum class Uart : uint8_t {
        Cmd = 0,
        BLE = 1,
        Log = 2,
        Unknown = 3,
    };

    inline message_t() : buf(nullptr), len(0), uart(Uart::Unknown) {}
    inline message_t(const uint8_t *b, uint32_t l, Uart u) : buf(b), len(l), uart(u) {}

    template <typename... Ts>
    inline error_t parse(Ts&&... ts) const {
        return decode(buf + 6, len - 8, std::forward<Ts>(ts)...);
    }

    uint16_t req() const {
        return decode_uint16(buf + 4);
    }

    template <typename... Ts>
    inline void write(uint16_t req, Ts&&... ts) const {
        switch (uart) {
            case Uart::BLE:
                driver::bleUart->write(req, std::forward<Ts>(ts)...);
            return;

            case Uart::Cmd:
                driver::cmdUart->write(req, std::forward<Ts>(ts)...);
            return;

            case Uart::Log:
                driver::logUart->write(req, std::forward<Ts>(ts)...);
            return;
			
			default: return;
        }
    }

    inline void nofity_step(uint8_t step, const error_t& err) const {
        write(proto::Action | proto::NotifyFlag, step, err);
    }

    const uint8_t *buf;
    uint32_t len;
    Uart uart;
};  

}

#endif
